package stattracker;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.swing.SwingWorker;

public class Halo3GamesFetcher
{
	ExecutorService threadManager;
	Halo3Data data;
	String startingURL;
	String lastUpdatedDate;
	int numPages, currPage;
	boolean reachedPrev, isCustoms;
	private StatTracker parent;
	private static final String GAME_INDICATOR = "ctl00_mainContent_bnetpgl_recentgames_ctl00";
	private static final String END_PLAYER_LIST = "</div></div></div></div>";
	private static final int MAX_GAMER_LEN = 20;
	
	public Halo3GamesFetcher(Halo3Data currentData, StatTracker p, boolean customs)
	{
		threadManager = Executors.newCachedThreadPool();
		
		isCustoms = customs;
		parent = p;
		numPages = 0; currPage = 1;
		data = currentData;
		
		startingURL = "http://www.bungie.net/stats/playerstatshalo3.aspx?player=" + data.getGamertag().replaceAll(" ", "%20");	
		reachedPrev = false;
		data.moreUpdate();
		if(customs)
		{
			startingURL += "&cus=1";
		}
		getGames(startingURL, customs);
		data.lessUpdate();
	}
	
	private void getGames(String url, boolean customs)
	{
		try
		{
			URL bungie = new URL(url);
			BufferedReader in = new BufferedReader(new InputStreamReader(bungie.openStream()));
			String inline;
			while((inline = in.readLine()) != null && ! reachedPrev)
			{
				if(numPages == 0 && inline.contains("items in")){
					numPages = parsePageCount(inline);
				}
				if(inline.contains(GAME_INDICATOR) && inline.contains(data.getGamertag()) && !inline.contains("rss.ashx"))
				{
					final String gameURL = ("http://www.bungie.net/" + parseGameURL(inline)).replaceAll(" ", "%20");
					final long gameID = getGameID(gameURL);
					if(data.hasSeen(gameID))
					{
						reachedPrev = true;
						break;
					}
					String gameType = parseGameType(inline);
					inline = in.readLine();
					inline = in.readLine();
					String date = parseSimpleGameData(inline);
					inline = in.readLine();
					inline = in.readLine();
					String map = parseSimpleGameData(inline);
					inline = in.readLine();
					inline = in.readLine();
					String playlist = parseSimpleGameData(inline);
					inline = in.readLine();
					inline = in.readLine();
					String placing = parseSimpleGameData(inline);

					final Halo3BasicGameData gameBase = new Halo3BasicGameData(gameType, date, map, playlist, placing, gameURL);
					final Halo3ComplexGameData gameDetail = new Halo3ComplexGameData();
					SwingWorker<Integer, Void> worker = new SwingWorker<Integer, Void>()
		            {
		    			public Integer doInBackground()
		    			{
							try
							{
								data.moreUpdate();
								parseDetailedGameData(gameBase, gameDetail, gameURL);
							}
							catch(Exception e)
							{
								gameDetail.brokenPage();
								new ErrorMessage("Problem getting detailed data.  Potentially bad URL generated.\n"+gameURL);
							}
							finally
							{
								data.lessUpdate();
							}
							return 1;
		    			}
		            };
		            threadManager.execute(worker);
		            
		            if(!reachedPrev)
						data.addGame(new Halo3GameData(gameID, gameBase, gameDetail));
				}
			}
			if(currPage < numPages && ! reachedPrev)
			{
				currPage++;
				//System.out.println("Current page: "+currPage);
				String nextURL = startingURL + "&ctl00_mainContent_bnetpgl_recentgamesChangePage="+currPage;
				//System.out.println("URL: " + nextURL);
				getGames(nextURL, customs);
			}
		}
		catch(MalformedURLException e){new ErrorMessage(e);}
		catch(IOException e){new ErrorMessage(e);}
	}
	
	private void parseDetailedGameData(Halo3BasicGameData base, Halo3ComplexGameData detail, String url) throws MalformedURLException, IOException
	{
		URL bungie = new URL(url);
		BufferedReader in = new BufferedReader(new InputStreamReader(bungie.openStream()));
		String inline;
		String searchFor = data.getGamertag() + "</a></span>";
		boolean finishedPlayers = false;
		ArrayList<String> otherGamers = new ArrayList<String>();
		int tab = 0;
		if(isCustoms)
			parent.setTitle("Updating Custom Games: " + data.getGamertag() + " Currently at: " + base.getDate());
		else
			parent.setTitle("Updating Matchmade Games: " + data.getGamertag() + " Currently at: " + base.getDate());
		boolean brokenGame = false;
		String color = "FFA";
		while((inline = in.readLine()) != null && !brokenGame)
		{
			if(inline.contains(END_PLAYER_LIST))
			{
				finishedPlayers = true;
				detail.setOtherGamers(otherGamers);
			}
			if(!finishedPlayers)
			{
				if(inline.contains("</a></span>"))
				{
					otherGamers.add(getOtherGamer(inline));
				}
			}
			if(inline.contains("Unfortunately, we don't have a record of this game or we have temporarily turned off game statistics."))
			{
				brokenGame = true;
				base.brokenPage();
				detail.brokenPage();
				break;
			}
			if(inline.contains("Length:"))
			{
				detail.setLength(getLength(inline));
				if(detail.getLength().charAt(0) == '-')
				{
					System.err.println(base.getURL());
					detail.setLength("00:08:00");
				}
				//System.out.println(part.length);
			}
			if(detail.getColor().equals("ffa") && inline.contains("span class=\"name\"") && inline.contains("Team"))
				color = getTeamColor(inline);
			if(inline.contains(searchFor))
			{
				tab++;
				if(tab == 1)
				{
					detail.setColor(color);
					inline = in.readLine();
					inline = in.readLine();
					String rank = isRankedGame(inline);
					detail.setIsRanked(rank.length() > 0);
					if(detail.isRanked())
						detail.setRank(Integer.parseInt(rank));
				}
				else if(tab == 2)
				{
					inline = in.readLine();
					inline = in.readLine();
					inline = in.readLine();
					inline = in.readLine();
					detail.setKills(getStatPiece(inline));
					
					inline = in.readLine();
					detail.setAssists(getStatPiece(inline));
					
					inline = in.readLine();
					detail.setDeaths(getStatPiece(inline));
					
					inline = in.readLine();
					inline = in.readLine();
					detail.setSuicides(getStatPiece(inline));
					
					inline = in.readLine();
					detail.setBetrayals(getStatPiece(inline));
					
					inline = in.readLine();
					detail.setScore(getStatPiece(inline));
					
					/*
					System.out.println(url);
					System.out.println(String.format("%s : %s : %s : %s : %s", base.getGameType(), base.getDate(), base.getMap(), base.getPlaylist(), base.getPlacement()));
					System.out.println(String.format("Kills: %d Assists: %d Deaths: %d Suicides: %d Betrayals: %d Score: %d",
							detail.getKills(), detail.getAssists(), detail.getDeaths(), detail.getSuicides(), detail.getBetrayals(), detail.getScore()));
							*/
				}
				else if(tab == 3)
				{
					if(detail.getKills() != 0)
					{
						while(!inline.contains("Total Weapon Breakdown"))
							inline = in.readLine();
						while(!inline.contains("<li class=\"hide\"><div class=\"clear\"/></li></ul>"))
						{
							inline = in.readLine();
							if(inline.length() > 40 && inline.contains("imgWepOfChoice"))
							{
								String weapName = getWeaponName(inline);
								int weapKills = getWeaponKills(inline);
								Weapon used = new Weapon(weapName, WeaponListUpdater.getImageLocation(weapName));
								used.setKillCount(weapKills);
								detail.addWeapon(used);
							}
						}
					}
				}
				else if(tab == 4)
				{
					
				}
				else{new ErrorMessage("Error went too far reprogram.");}
			}
			if(inline.replaceAll(" ", "").equals(data.getGamertag().replaceAll(" ", "")))
			{
				for(int i = 0; i < 26; i++)
					inline = in.readLine();
				while(!inline.contains("<!-- =total_medals -->"))
				{
					if(inline.contains(".gif"))
					{
						for(Medal m : new MedalListUpdater().getMedalList())
						{
							if(inline.contains(m.getBungieLoc()))
							{
								Medal got = new Medal(m.getName(), m.getImgLoc(), m.getBungieLoc(), m.getDifficulty());
								inline = in.readLine();
								got.setMedalCount(getMedAmount(inline));
								//System.out.println(String.format("%s : %d", got.name, got.amt));
								detail.addMedal(got);
							}
						}
					}
					inline = in.readLine();
				}
			}
		}
		/*	
		for(Medal m : part.medalsEarned)
			System.out.println(m.name + " x " + m.amt);*/
	}
	
	private String getOtherGamer(String htmlLine) {
		int approxStart = (htmlLine.indexOf("</a></span>") - MAX_GAMER_LEN);
		int start = htmlLine.indexOf(">", approxStart) + 1;
		return htmlLine.substring(start, htmlLine.indexOf("<", start));
	}

	private String getTeamColor(String htmlLine)
	{
		int start = htmlLine.indexOf(">");
		return htmlLine.substring(start+1, htmlLine.indexOf("<", start));
	}
	
	private int getGameID(String url)
	{
		int start = url.indexOf("gameid=");
		return Integer.parseInt(url.substring(start+7, url.indexOf("&")));
	}
	
	private String isRankedGame(String htmlLine)
	{
		int start = htmlLine.indexOf(">");
		return htmlLine.substring(start+1, htmlLine.indexOf("<", start));
	}
	
	private int getWeaponKills(String htmlLine)
	{
		int start = htmlLine.indexOf("wl_kill\">")+9;
		return Integer.parseInt(htmlLine.substring(start, htmlLine.indexOf(" ", start)));
	}
	
	private String getWeaponName(String htmlLine)
	{
		int start = htmlLine.indexOf("wl_name\">")+9;
		return htmlLine.substring(start, htmlLine.indexOf("<", start)-1);
	}
	
	private String getLength(String htmlLine)
	{
		String len = htmlLine.substring(28, 36);
		if(len.charAt(0) == '-')
			return "00:09:00";
		return len;
	}
	
	private int getMedAmount(String htmlLine)
	{
		int start = htmlLine.indexOf(">");
		return Integer.parseInt(htmlLine.substring(start+1, htmlLine.indexOf("<", start)));
	}
	
	private int getStatPiece(String htmlLine)
	{
		int start = htmlLine.indexOf(">");
		String data = htmlLine.substring(start+1, htmlLine.indexOf("<", start));
		if(data.charAt(0) == '+')
			data = data.substring(1, data.length());
		if(data.equals("-") || data.equals("N/A"))
			data = "0";
		return Integer.parseInt(data);
	}

	private String parseSimpleGameData(String htmlLine)
	{
		return htmlLine.trim();
	}
	
	private String parseGameType(String htmlLine) 
	{
		int start = htmlLine.indexOf(">");
		return htmlLine.substring(start+1, htmlLine.indexOf("<", start));
	}
	
	private String parseGameURL(String htmlLine) 
	{
		int href = htmlLine.indexOf("href=")+7;
		return htmlLine.substring(href, htmlLine.indexOf("\"", href));
	}
	
	private int parsePageCount(String htmlLine)
	{
		int start = htmlLine.indexOf("in");
		start = htmlLine.indexOf(">", start);
		return Integer.parseInt(htmlLine.substring(start+1, htmlLine.indexOf("<", start)));
	}
}
